Skip to content

feat: add scope checks#113

Merged
gfyrag merged 1 commit intomainfrom
fix/add-scopes
Nov 6, 2025
Merged

feat: add scope checks#113
gfyrag merged 1 commit intomainfrom
fix/add-scopes

Conversation

@gfyrag
Copy link
Contributor

@gfyrag gfyrag commented Oct 24, 2025

Summary by CodeRabbit

  • New Features

    • Optional scope-checking toggle to enable protection of client and user endpoints; new auth module wiring.
  • Bug Fixes

    • Metadata fields now accept only string values, tightening validation and consistency.
  • Chores

    • SDK and dependency updates.
    • Legacy authorization middleware and its tests removed; router wiring updated to use new auth plumbing.
    • Extensive end-to-end OAuth2 client/secret tests added and testserver scope flag introduced.
    • API docs/models updated to reflect metadata type change.

@coderabbitai
Copy link

coderabbitai bot commented Oct 24, 2025

Walkthrough

Removed in-repo access-token verification and its middleware/tests; routes now accept injected authlib authenticators and are wrapped with authlib middleware. Server wiring adds delegated auth module, static OIDC KeySet provider and a scope-check flag. Client Metadata types and OpenAPI schema tightened; dependencies and E2E tests updated.

Changes

Cohort / File(s) Change Summary
Removed local auth logic & tests
pkg/api/authorization/accesstoken.go, pkg/api/authorization/middleware.go, pkg/api/authorization/accesstoken_test.go, pkg/api/authorization/main_test.go
Deleted local token verification function, authorization middleware, related error constants, and associated tests/test harness.
Routes accept injected authenticator
pkg/api/clients.go, pkg/api/users.go, pkg/api/clients_test.go, pkg/api/users_test.go
addClientRoutes and addUserRoutes signatures now accept authlib.Authenticator and routes are wrapped with authlib.Middleware(authenticator); tests updated to call with authlib.NewNoAuth().
Router/module and serve CLI wiring
pkg/api/module.go, cmd/serve.go
CreateRootRouter signature simplified (removed op.OpenIDProvider); cmd/serve.go adds authlib.Module wiring with a CheckScopes flag, provides a static oidclib.KeySet from the signing key, and refactors OTLP HTTP client provisioning.
Testserver & E2E tests
pkg/testserver/server.go, test/e2e/oauth2_clients_test.go, test/e2e/client_credentials_test.go
Configuration gains CheckScopes bool; comprehensive OAuth2 clients E2E tests added; client-credentials test adds auth:write scope and testserver wiring updated.
Client SDK & docs: metadata type change and SDK bump
pkg/client/models/components/*.go, pkg/client/docs/models/components/*.md, pkg/client/formance.go
Metadata types changed from map[string]any/map[string]*any to map[string]string/map[string]*string across models and docs; SDK version bumped 0.7.1 → 0.7.2 and UserAgent updated.
OIDC storage constant
pkg/oidc/storage.go
Added exported KeyID = "id" constant and used it for signingKey.id in storage initialization.
Go modules & CI config
go.mod, .github/dependabot.yml, .coderabbit.yaml, openapi.yaml
Dependency updates in go.mod; removed Dependabot config; added .coderabbit.yaml with path filter; tightened openapi.yaml Metadata additionalProperties to type: string.

Sequence Diagram(s)

sequenceDiagram
    participant C as Client
    participant M as authlib.Middleware
    participant A as Authenticator (injected)
    participant K as oidclib.KeySet / Auth Module
    participant H as API Handler

    C->>M: HTTP Request (may include Authorization)
    M->>A: Authenticate request (parse token / claims)
    alt delegated verification required
        A->>K: Verify token & scopes (JWK/OIDC)
        K-->>A: verification result
    end
    alt token invalid or missing
        M-->>C: 401 Unauthorized
    else insufficient scopes
        M-->>C: 403 Forbidden
    else authenticated
        M->>H: Forward request with identity context
        H-->>C: 200 / resource response
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Review call-site updates for addClientRoutes / addUserRoutes across the repo and tests.
  • Verify no remaining references to the removed verifyAccessToken function or authorization package.
  • Validate fx wiring, the new authlib.Module usage, and the static oidclib.KeySet provider.
  • Confirm metadata type changes align between models, OpenAPI, and client SDK code.
  • Inspect added E2E tests and pkg/testserver CheckScopes behavior.

Poem

🐇 I hopped past middleware, left tokens in a trail,
New keys glint where old checks used to fail.
Routes don cloaks of auth, snug and neat,
I nibble scopes and twitch my happy feet.
Hooray — tidy hops and code that’s fleet.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add scope checks' directly and clearly summarizes the main change: introducing scope checking functionality to the authorization system.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/add-scopes

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
pkg/api/authorization/accesstoken_test.go (2)

109-110: Consider verifying the claims content for unprotected routes.

The test captures the error but doesn't verify that claims is nil for unprotected routes. While the current test is correct, explicitly asserting require.Nil(t, claims) would better document the expected behavior.

-		_, err = verifyAccessToken(req, provider)
+		claims, err := verifyAccessToken(req, provider)
 		require.NoError(t, err)
+		require.Nil(t, claims)

158-159: Add test coverage for claims content on successful verification.

The test verifies that no error is returned but doesn't check that claims are properly populated. Consider adding assertions to verify the claims structure and content.

-		_, err = verifyAccessToken(req, provider)
+		claims, err := verifyAccessToken(req, provider)
 		require.NoError(t, err)
+		require.NotNil(t, claims)
+		// Optionally verify specific claims fields
pkg/api/authorization/middleware.go (2)

3-8: Reorder imports to follow Go conventions.

Standard library imports should be separated from third-party imports with a blank line.

 import (
     "errors"
-    "github.com/formancehq/go-libs/v3/collectionutils"
-    "github.com/zitadel/oidc/v2/pkg/op"
     "net/http"
+
+    "github.com/formancehq/go-libs/v3/collectionutils"
+    "github.com/zitadel/oidc/v2/pkg/op"
 )

28-31: Consider extracting scope validation into a helper function.

The scope checking logic is duplicated with multiple calls to collectionutils.Contains. Extracting this into a helper function would improve maintainability and make the authorization logic clearer.

Add a helper function before the middleware:

func hasRequiredScope(scopes []string, method string) bool {
    hasRead := collectionutils.Contains(scopes, "auth:read")
    hasWrite := collectionutils.Contains(scopes, "auth:write")
    
    switch method {
    case http.MethodOptions, http.MethodGet, http.MethodHead, http.MethodTrace:
        return hasRead || hasWrite
    default:
        return hasWrite
    }
}

Then use it in the middleware:

-allowed := true
-switch r.Method {
-case http.MethodOptions, http.MethodGet, http.MethodHead, http.MethodTrace:
-    allowed = allowed && (collectionutils.Contains(claims.Scopes, "auth:read") || collectionutils.Contains(claims.Scopes, "auth:write"))
-default:
-    allowed = allowed && collectionutils.Contains(claims.Scopes, "auth:write")
-}
-
-if !allowed {
+if !hasRequiredScope(claims.Scopes, r.Method) {
     http.Error(w, "forbidden", http.StatusForbidden)
     return
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 69aae1a and ee0a654.

⛔ Files ignored due to path filters (1)
  • .github/dependabot.yml is excluded by !**/*.yml
📒 Files selected for processing (3)
  • pkg/api/authorization/accesstoken.go (1 hunks)
  • pkg/api/authorization/accesstoken_test.go (5 hunks)
  • pkg/api/authorization/middleware.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
pkg/api/authorization/accesstoken.go (1)
pkg/api/authorization/middleware.go (3)
  • ErrMissingAuthHeader (11-11)
  • ErrMalformedAuthHeader (12-12)
  • ErrVerifyAuthToken (13-13)
pkg/api/authorization/middleware.go (1)
pkg/client/internal/utils/utils.go (1)
  • Contains (59-66)
🔇 Additional comments (1)
pkg/api/authorization/accesstoken.go (1)

30-30: LGTM: Claims extraction is correct.

The use of op.VerifyAccessToken[*oidc.AccessTokenClaims] correctly captures the token claims for downstream authorization logic.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
pkg/api/authorization/middleware.go (2)

34-40: The refactor suggestion from previous review remains applicable.

The authorization logic uses a redundant pattern (allowed := true followed by allowed = allowed && ...). The previous review's suggestion to simplify this logic is still valid and would improve readability.

Apply the diff from the previous review:

-allowed := true
+var allowed bool
 switch r.Method {
 case http.MethodOptions, http.MethodGet, http.MethodHead, http.MethodTrace:
-    allowed = allowed && (collectionutils.Contains(claims.Scopes, "auth:read") || collectionutils.Contains(claims.Scopes, "auth:write"))
+    allowed = collectionutils.Contains(claims.Scopes, "auth:read") || collectionutils.Contains(claims.Scopes, "auth:write")
 default:
-    allowed = allowed && collectionutils.Contains(claims.Scopes, "auth:write")
+    allowed = collectionutils.Contains(claims.Scopes, "auth:write")
 }

28-32: Critical: The nil check issue flagged in previous review is still unresolved.

This critical issue was already identified in a previous review and remains unfixed. When verifyAccessToken returns (nil, nil) for unprotected routes, the code proceeds to access claims.Scopes at line 37, causing a nil pointer dereference panic.

The fix from the previous review should be applied:

 claims, err := verifyAccessToken(r, o)
 if err != nil {
     http.Error(w, err.Error(), http.StatusUnauthorized)
     return
 }
 
+// Skip authorization for unprotected routes
+if claims == nil {
+    h.ServeHTTP(w, r)
+    return
+}
+
 allowed := true
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ee0a654 and 26acfed.

⛔ Files ignored due to path filters (1)
  • .github/dependabot.yml is excluded by !**/*.yml
📒 Files selected for processing (4)
  • pkg/api/authorization/accesstoken.go (1 hunks)
  • pkg/api/authorization/accesstoken_test.go (4 hunks)
  • pkg/api/authorization/middleware.go (2 hunks)
  • test/e2e/client_credentials_test.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/api/authorization/accesstoken_test.go
  • pkg/api/authorization/accesstoken.go
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/api/authorization/middleware.go (1)
pkg/client/internal/utils/utils.go (1)
  • Contains (59-66)
🔇 Additional comments (4)
pkg/api/authorization/middleware.go (2)

3-9: LGTM!

The new imports appropriately support the scope-checking functionality (collectionutils for Contains, strings for HasPrefix).


42-45: LGTM!

The forbidden response logic correctly returns a 403 status when scope authorization fails.

test/e2e/client_credentials_test.go (2)

46-46: LGTM!

Adding the auth:write scope to the static client configuration correctly aligns with the new authorization requirements in the middleware.


60-60: LGTM!

Adding the auth:write scope to the client credentials configuration ensures the test obtains tokens with the necessary permissions for write operations, aligning with the middleware's authorization checks.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/api/module.go (1)

58-64: Fix the unused op.OpenIDProvider dependency

With CreateRootRouter no longer using the provider, the injected parameter o op.OpenIDProvider is now unused, which will fail go build because Go rejects unused variables. Either rename it to _ or drop the dependency entirely.

-		fx.Invoke(func(lc fx.Lifecycle, r chi.Router, healthController *health.HealthController, o op.OpenIDProvider) {
+		fx.Invoke(func(lc fx.Lifecycle, r chi.Router, healthController *health.HealthController, _ op.OpenIDProvider) {
🧹 Nitpick comments (1)
pkg/api/users_test.go (1)

90-90: Consider adding tests for authentication and scope validation.

While using authlib.NewNoAuth() is appropriate for unit tests focused on business logic, the PR objective is to add scope checks. Consider adding integration tests that:

  1. Verify that unauthenticated requests to /users endpoints are rejected
  2. Verify that authenticated requests without required scopes are rejected
  3. Verify that authenticated requests with proper scopes succeed

This would ensure the authentication middleware and scope checks are working as intended.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 26acfed and faa1543.

⛔ Files ignored due to path filters (3)
  • .github/dependabot.yml is excluded by !**/*.yml
  • go.mod is excluded by !**/*.mod
  • go.sum is excluded by !**/*.sum, !**/*.sum
📒 Files selected for processing (12)
  • cmd/serve.go (4 hunks)
  • pkg/api/authorization/accesstoken.go (0 hunks)
  • pkg/api/authorization/accesstoken_test.go (0 hunks)
  • pkg/api/authorization/main_test.go (0 hunks)
  • pkg/api/authorization/middleware.go (0 hunks)
  • pkg/api/clients.go (2 hunks)
  • pkg/api/clients_test.go (2 hunks)
  • pkg/api/module.go (2 hunks)
  • pkg/api/users.go (2 hunks)
  • pkg/api/users_test.go (2 hunks)
  • pkg/oidc/storage.go (1 hunks)
  • test/e2e/client_credentials_test.go (2 hunks)
💤 Files with no reviewable changes (4)
  • pkg/api/authorization/accesstoken.go
  • pkg/api/authorization/accesstoken_test.go
  • pkg/api/authorization/main_test.go
  • pkg/api/authorization/middleware.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/e2e/client_credentials_test.go
🧰 Additional context used
🧬 Code graph analysis (2)
pkg/api/module.go (1)
pkg/testserver/server.go (1)
  • Logger (63-65)
cmd/serve.go (5)
pkg/api/module.go (1)
  • Module (46-66)
pkg/storage/sqlstorage/module.go (1)
  • Module (19-40)
pkg/oidc/module.go (1)
  • Module (19-43)
pkg/delegatedauth/module.go (1)
  • Module (10-17)
pkg/oidc/storage.go (2)
  • Service (89-91)
  • KeyID (551-551)
🔇 Additional comments (3)
pkg/api/users.go (2)

4-4: LGTM: Import added for authentication support.

The import addition is necessary for the authentication middleware integration.


14-21: Add documentation for required scopes on user endpoints.

The /users endpoints are wrapped with authlib.Middleware, but scope enforcement cannot be verified from this codebase since the middleware is implemented in an external package (github.com/formancehq/go-libs/v3/auth).

Scopes are defined in the generated client code (pkg/client/v1.go): both listUsers and readUser require "auth:read". However, the handler functions lack documentation about these scope requirements, making the intent unclear.

Add comments above the route handlers documenting the required scopes:

// Requires "auth:read" scope
r.Get("/", listUsers(db))

This improves code maintainability and clarifies security requirements, especially if scope validation is delegated to the middleware layer.

pkg/api/users_test.go (1)

5-5: LGTM: Import added for test authenticator.

The import is necessary to provide the NewNoAuth() authenticator for test setup.

@gfyrag gfyrag force-pushed the fix/add-scopes branch 2 times, most recently from 9ec43ed to 5d44230 Compare November 5, 2025 15:44
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between faa1543 and 5d44230.

⛔ Files ignored due to path filters (16)
  • go.sum is excluded by !**/*.sum
  • pkg/client/.speakeasy/gen.lock is excluded by !**/*.lock, !pkg/client/**
  • pkg/client/.speakeasy/gen.yaml is excluded by !pkg/client/**
  • pkg/client/docs/models/components/client.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/clientsecret.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/createclientrequest.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/createsecretrequest.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/secret.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/updateclientrequest.md is excluded by !pkg/client/**
  • pkg/client/formance.go is excluded by !pkg/client/**
  • pkg/client/models/components/client.go is excluded by !pkg/client/**
  • pkg/client/models/components/clientsecret.go is excluded by !pkg/client/**
  • pkg/client/models/components/createclientrequest.go is excluded by !pkg/client/**
  • pkg/client/models/components/createsecretrequest.go is excluded by !pkg/client/**
  • pkg/client/models/components/secret.go is excluded by !pkg/client/**
  • pkg/client/models/components/updateclientrequest.go is excluded by !pkg/client/**
📒 Files selected for processing (18)
  • .coderabbit.yaml (1 hunks)
  • .github/dependabot.yml (0 hunks)
  • cmd/serve.go (4 hunks)
  • go.mod (6 hunks)
  • openapi.yaml (1 hunks)
  • pkg/api/authorization/accesstoken.go (0 hunks)
  • pkg/api/authorization/accesstoken_test.go (0 hunks)
  • pkg/api/authorization/main_test.go (0 hunks)
  • pkg/api/authorization/middleware.go (0 hunks)
  • pkg/api/clients.go (3 hunks)
  • pkg/api/clients_test.go (2 hunks)
  • pkg/api/module.go (2 hunks)
  • pkg/api/users.go (2 hunks)
  • pkg/api/users_test.go (2 hunks)
  • pkg/oidc/storage.go (1 hunks)
  • pkg/testserver/server.go (3 hunks)
  • test/e2e/client_credentials_test.go (2 hunks)
  • test/e2e/oauth2_clients_test.go (1 hunks)
💤 Files with no reviewable changes (5)
  • pkg/api/authorization/accesstoken.go
  • pkg/api/authorization/middleware.go
  • pkg/api/authorization/accesstoken_test.go
  • .github/dependabot.yml
  • pkg/api/authorization/main_test.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • pkg/testserver/server.go
  • pkg/api/users.go
  • pkg/oidc/storage.go
  • pkg/api/clients.go
  • test/e2e/client_credentials_test.go
🧰 Additional context used
🧬 Code graph analysis (2)
test/e2e/oauth2_clients_test.go (10)
pkg/testserver/server.go (4)
  • Server (69-77)
  • New (279-299)
  • Configuration (54-63)
  • DelegatedConfiguration (42-46)
pkg/client/models/components/clientsecret.go (1)
  • ClientSecret (5-10)
pkg/client.go (2)
  • StaticClient (118-121)
  • ClientOptions (154-164)
pkg/client/models/components/client.go (1)
  • Client (5-16)
pkg/client/models/components/createclientrequest.go (1)
  • CreateClientRequest (5-14)
pkg/client/models/operations/readclient.go (1)
  • ReadClientRequest (9-12)
pkg/client/models/components/updateclientrequest.go (1)
  • UpdateClientRequest (5-14)
pkg/client/models/operations/deleteclient.go (2)
  • DeleteClientResponse (21-23)
  • DeleteClientRequest (9-12)
pkg/client/models/components/createsecretrequest.go (1)
  • CreateSecretRequest (5-8)
pkg/client/models/operations/deletesecret.go (1)
  • DeleteSecretRequest (9-14)
cmd/serve.go (5)
pkg/api/module.go (1)
  • Module (46-66)
pkg/storage/sqlstorage/module.go (1)
  • Module (19-40)
pkg/oidc/module.go (1)
  • Module (19-43)
pkg/delegatedauth/module.go (1)
  • Module (10-17)
pkg/oidc/storage.go (2)
  • Service (89-91)
  • KeyID (551-551)
🔇 Additional comments (9)
.coderabbit.yaml (1)

1-3: Verify intent: Excluding pkg/client/** from review coverage.

The configuration excludes the entire pkg/client directory from CodeRabbit reviews. According to the PR summary, this directory contains "extensive changes to client-related data models." Please confirm this exclusion is intentional, especially if these client changes represent material modifications that should undergo review.

If the exclusion is necessary (e.g., auto-generated or machine-formatted code), consider adding a clarifying comment or narrowing the pattern to exclude only generated files.

go.mod (3)

96-98: Verify new transitive dependencies are necessary and properly constrained.

The following new indirect dependencies were introduced:

  • github.com/hashicorp/go-cleanhttp v0.5.2 and github.com/hashicorp/go-retryablehttp v0.7.8 (HTTP retry/cleanup utilities)
  • github.com/zitadel/oidc/v3 v3.45.0 and github.com/zitadel/schema v1.3.1 (OIDC schema support)

These appear to be pulled in transitively (possibly through go-libs/v3 update on line 11). Confirm that:

  1. These dependencies are intentional and required for scope checking.
  2. The go-libs/v3 version bump (line 11) is the source of these transitive deps.
  3. No version conflicts arise from these additions.

Also applies to: 145-146


26-26: Confirm OTEL version coherence is intentional; minor-version backward compatibility supports the current configuration.

OpenTelemetry SDK packages must remain backwards compatible, and the v1.37.0 to v1.38.0 bump is a semantic minor-version update. The verified mismatch—core/trace at v1.38.0 and exporters at v1.37.0—should not introduce runtime incompatibilities. However, ensure this versioning strategy is deliberate and aligns with your dependency management approach.


11-29: The review comment is incorrect—these dependency patterns are standard and verified.

Go's module system handles multiple major versions correctly when import paths differ. The go mod verify check passes, confirming no actual conflicts exist. The coexistence of:

  • zitadel/oidc/v2@v2.12.2 (direct) and zitadel/oidc/v3@v3.45.0 (direct)
  • go-jose/v4 alongside gopkg.in/go-jose/go-jose.v2 and gopkg.in/square/go-jose.v2

...is expected behavior—each represents a separate, importable package. Additionally, golang.org/x/oauth2 v0.31.0 introduces no breaking changes; it only updates the Go toolchain requirement to 1.24.0.

The changes are valid and impose no compatibility risks.

Likely an incorrect or invalid review comment.

pkg/api/users_test.go (1)

90-90: Authenticator injection keeps unit tests aligned

authlib.NewNoAuth() satisfies the new route signature without introducing auth side effects, so the existing handler assertions still run unchanged.

pkg/api/clients_test.go (1)

44-44: No-op authenticator keeps client tests focused

Routing now accepts the authenticator, and passing authlib.NewNoAuth() lets the suite exercise the handlers without layering authentication concerns.

cmd/serve.go (1)

202-208: Static KeySet ensures local token verification

Decorating the oidclib.KeySet with the server’s own RSA public key means authlib doesn’t reach out to remote JWKS and the new scope checks operate against a deterministic signing source.

pkg/api/module.go (1)

18-39: Issuer propagation preserved after auth refactor

Populating op.ContextWithIssuer in the router middleware keeps downstream handlers aware of the issuer even after removing the old authorization layer, so existing OIDC-dependent code continues to work.

test/e2e/oauth2_clients_test.go (1)

620-739: End-to-end scope coverage looks solid

Exercising the client flows again with an access token lacking auth:write gives us confidence the new scope checks reject every CRUD path, matching the production expectations.

@gfyrag gfyrag force-pushed the fix/add-scopes branch 2 times, most recently from 0af8f5d to 6307dad Compare November 5, 2025 16:41
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
pkg/api/module.go (1)

58-58: Consider removing unused OpenIDProvider parameter.

The o op.OpenIDProvider parameter appears unused in the function body. If it's no longer needed after the auth refactor, remove it for clarity.

If it's not needed, apply this diff:

-		fx.Invoke(func(lc fx.Lifecycle, r chi.Router, healthController *health.HealthController, o op.OpenIDProvider) {
+		fx.Invoke(func(lc fx.Lifecycle, r chi.Router, healthController *health.HealthController) {

Alternatively, run this script to check if OpenIDProvider initialization has necessary side-effects elsewhere:

#!/bin/bash
# Description: Check if OpenIDProvider is constructed/used elsewhere in the module for side-effects

# Find OpenIDProvider construction or configuration
rg -n 'op\.OpenIDProvider|NewOpenIDProvider' --type go -C 5
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5d44230 and 0af8f5d.

⛔ Files ignored due to path filters (16)
  • go.sum is excluded by !**/*.sum
  • pkg/client/.speakeasy/gen.lock is excluded by !**/*.lock, !pkg/client/**
  • pkg/client/.speakeasy/gen.yaml is excluded by !pkg/client/**
  • pkg/client/docs/models/components/client.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/clientsecret.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/createclientrequest.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/createsecretrequest.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/secret.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/updateclientrequest.md is excluded by !pkg/client/**
  • pkg/client/formance.go is excluded by !pkg/client/**
  • pkg/client/models/components/client.go is excluded by !pkg/client/**
  • pkg/client/models/components/clientsecret.go is excluded by !pkg/client/**
  • pkg/client/models/components/createclientrequest.go is excluded by !pkg/client/**
  • pkg/client/models/components/createsecretrequest.go is excluded by !pkg/client/**
  • pkg/client/models/components/secret.go is excluded by !pkg/client/**
  • pkg/client/models/components/updateclientrequest.go is excluded by !pkg/client/**
📒 Files selected for processing (18)
  • .coderabbit.yaml (1 hunks)
  • .github/dependabot.yml (0 hunks)
  • cmd/serve.go (4 hunks)
  • go.mod (6 hunks)
  • openapi.yaml (1 hunks)
  • pkg/api/authorization/accesstoken.go (0 hunks)
  • pkg/api/authorization/accesstoken_test.go (0 hunks)
  • pkg/api/authorization/main_test.go (0 hunks)
  • pkg/api/authorization/middleware.go (0 hunks)
  • pkg/api/clients.go (3 hunks)
  • pkg/api/clients_test.go (2 hunks)
  • pkg/api/module.go (2 hunks)
  • pkg/api/users.go (2 hunks)
  • pkg/api/users_test.go (2 hunks)
  • pkg/oidc/storage.go (1 hunks)
  • pkg/testserver/server.go (3 hunks)
  • test/e2e/client_credentials_test.go (2 hunks)
  • test/e2e/oauth2_clients_test.go (1 hunks)
💤 Files with no reviewable changes (5)
  • pkg/api/authorization/middleware.go
  • pkg/api/authorization/main_test.go
  • pkg/api/authorization/accesstoken.go
  • pkg/api/authorization/accesstoken_test.go
  • .github/dependabot.yml
🚧 Files skipped from review as they are similar to previous changes (5)
  • openapi.yaml
  • pkg/oidc/storage.go
  • test/e2e/client_credentials_test.go
  • pkg/api/clients_test.go
  • pkg/api/clients.go
🧰 Additional context used
🧬 Code graph analysis (2)
cmd/serve.go (4)
pkg/api/module.go (1)
  • Module (46-66)
pkg/storage/sqlstorage/module.go (1)
  • Module (19-40)
pkg/oidc/module.go (1)
  • Module (19-43)
pkg/oidc/storage.go (2)
  • Service (89-91)
  • KeyID (551-551)
test/e2e/oauth2_clients_test.go (11)
pkg/testserver/server.go (4)
  • Server (69-77)
  • New (279-299)
  • Configuration (54-63)
  • DelegatedConfiguration (42-46)
pkg/client/formance.go (1)
  • New (141-171)
pkg/client/models/components/clientsecret.go (1)
  • ClientSecret (5-10)
pkg/client.go (2)
  • StaticClient (118-121)
  • ClientOptions (154-164)
pkg/client/models/components/client.go (1)
  • Client (5-16)
pkg/client/models/components/createclientrequest.go (1)
  • CreateClientRequest (5-14)
pkg/client/models/operations/readclient.go (1)
  • ReadClientRequest (9-12)
pkg/client/models/components/updateclientrequest.go (1)
  • UpdateClientRequest (5-14)
pkg/client/models/operations/deleteclient.go (1)
  • DeleteClientRequest (9-12)
pkg/client/models/components/createsecretrequest.go (1)
  • CreateSecretRequest (5-8)
pkg/client/models/operations/deletesecret.go (1)
  • DeleteSecretRequest (9-14)
🔇 Additional comments (27)
.coderabbit.yaml (1)

1-3: ****

The exclusion of pkg/client/** from CodeRabbit reviews is intentional and correct. The pkg/client directory contains a Speakeasy-generated OpenAPI SDK, not manually maintained source code. The repository's CONTRIBUTING.md explicitly states this directory contains generated code and does not accept direct changes. The metadata type changes observed in this PR (from map[string]*any* to map[string]*string*) are automatically regenerated stubs from an updated OpenAPI specification version (0.7.2), not hand-written code requiring review. Excluding auto-generated artifacts from CodeRabbit follows best practices and the project's established policy.

Likely an incorrect or invalid review comment.

pkg/testserver/server.go (3)

7-7: LGTM! Clean import alias.

The import alias authlib is clear and prevents naming conflicts with the local auth package.


62-62: LGTM! Configuration field added.

The CheckScopes field appropriately extends the test server configuration to support scope checking in tests.


190-192: LGTM! Scope check flag properly wired.

The conditional logic correctly appends the scope check flag when enabled in the configuration.

pkg/api/users_test.go (2)

5-5: LGTM! Import added for authentication support.


90-90: LGTM! Test updated to match new API signature.

The use of authlib.NewNoAuth() is appropriate for unit tests that don't need authentication enforcement.

pkg/api/users.go (2)

4-4: LGTM! Import added for authentication support.


14-21: LGTM! Routes properly protected with authentication middleware and all callers have been updated.

The function signature change to include an authenticator parameter and the use of authlib.Middleware(authenticator) correctly implements the scope checking functionality. Verification confirms the only caller in pkg/api/users_test.go:90 has been updated with the new 3-parameter signature.

cmd/serve.go (6)

8-10: LGTM! Imports added for authentication and OIDC support.


82-99: LGTM! HTTP client extraction improves reusability.

Extracting otlpHttpClient as a standalone function is a good refactor that makes the HTTP client configuration reusable.


114-114: LGTM! Scope checking flag added.

The AuthCheckScopesFlag properly enables scope checking functionality as per the PR objectives.


180-180: LGTM! Flag value properly read.


186-194: Reformatting is consistent.

The multi-line formatting of api.Module arguments improves readability.


195-208: LGTM! Authentication module properly configured.

The authlib.Module configuration correctly wires up the authentication with:

  • Enabled flag
  • Issuer set to baseUrl
  • CheckScopes flag from CLI
  • Service name

The oidclib.KeySet provider using the RSA public key from the signing key is properly implemented. The KeyID references oidc.KeyID which should be consistent with the key identifier used elsewhere in the OIDC implementation.

test/e2e/oauth2_clients_test.go (9)

1-21: LGTM! Clean test setup with proper imports.

The build tag //go:build it correctly isolates integration tests, and the imports are well-organized.


22-52: LGTM! Well-structured test server configuration.

The test setup properly configures:

  • PostgreSQL database connection
  • Delegated OIDC configuration with mockOIDC
  • A static client with auth:write scope for testing
  • CheckScopes: true to enable scope verification

This provides a realistic test environment for validating the scope checking functionality.


54-140: LGTM! Comprehensive client creation tests.

The tests validate:

  • Minimal client creation (name only)
  • Full client creation with all fields
  • Proper field persistence and defaults

Good coverage of the create endpoint.


142-200: LGTM! Thorough client read tests.

Tests cover both successful reads of existing clients and error handling for non-existent clients.


202-275: LGTM! Comprehensive client listing tests.

The tests validate:

  • Successful listing of multiple clients
  • Client details are properly returned
  • Filtering/inclusion of created clients

277-369: LGTM! Complete client update tests.

Tests cover:

  • Successful updates with all fields
  • Persistence verification by re-reading the client
  • Error handling for non-existent clients

371-429: LGTM! Client deletion tests with idempotency check.

The tests properly validate:

  • Successful deletion of existing clients
  • Verification that the client is removed
  • Idempotent behavior for deleting non-existent clients

The use of BeElementOf(http.StatusNoContent, http.StatusNotFound) on line 426 correctly handles both possible idempotent responses.


431-572: LGTM! Comprehensive secret management tests.

Excellent coverage of:

  • Creating secrets with metadata
  • Validating clear text is returned only on creation
  • Multiple secrets per client
  • Secret deletion
  • Error cases for non-existent clients/secrets

The test on lines 476-487 properly validates that secrets are added to the client.


575-741: LGTM! Excellent authorization tests.

The unauthorized client tests thoroughly validate that operations are properly denied when the client lacks the auth:write scope:

  • Create client
  • List clients
  • Read client
  • Update client
  • Delete client
  • Create secret
  • Delete secret

This provides strong validation of the scope checking functionality introduced in this PR.

go.mod (2)

11-11: No action required. The go-libs/v3 version is valid and accessible. The authlib/auth module is actively imported and used across 6 files in the codebase (cmd/serve.go, pkg/testserver/server.go, pkg/api/users.go, pkg/api/clients.go, and their test files), confirming the pre-release version intentionally includes the required functionality.


13-13: No issues found—go-jose v4.1.3 is the latest version and contains all security patches.

Verification confirms that go-jose/v4 v4.1.3 is the latest available version (released October 2025) and is not affected by any known security vulnerabilities. The two identified advisories (DoS and Data Amplification) are patched in v4.0.5 and v4.0.1 respectively, both of which are older than the current version. The dependency is secure.

pkg/api/module.go (2)

50-52: LGTM!

The fx.Provide wiring correctly updated to match the new CreateRootRouter signature, properly injecting the logger while capturing issuer and debug from the module scope.


18-22: Now I need to examine the actual file to verify the line 58 concern and see the complete Module function:

Based on the executed rg script output, I can now verify the original review comment:

Verification Summary:

The search found the CreateRootRouter function and its usage:

  • Line 18: Function definition with new signature (logger, issuer, debug) - removes OpenIDProvider ✓
  • Line 51: Single call site in fx.Provide wrapper calling CreateRootRouter(logger, issuer, debug) - matches new signature ✓

The original review's main concern has been verified as correct: all callers of CreateRootRouter have been updated to match the new signature. There is only one call site in the codebase (at line 51), and it has been properly updated with the 3-parameter call matching the new function signature.


LGTM: All callers of CreateRootRouter have been correctly updated to match the new signature.

The signature change successfully removes the OpenIDProvider parameter, aligning with the PR's goal to shift away from local token verification toward delegated authentication. The router middleware chain continues to propagate the issuer via context as intended.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
openapi.yaml (1)

256-257: Breaking API change already flagged in previous review—verify resolution completeness.

This Metadata.additionalProperties change (from unrestricted to type: string) was comprehensively analyzed in a previous review and flagged as a critical breaking change. That review indicated it was addressed in commit 0af8f5d.

To confirm the resolution is complete, verify that:

  • CHANGELOG or release notes document this breaking change
  • Migration guidance is provided for consumers passing non-string metadata values
  • This change is clearly communicated in the release notes for the affected version

If documentation updates were included in commit 0af8f5d, feel free to disregard this note. Otherwise, ensure consumer-facing guidance is added before release.

🧹 Nitpick comments (2)
pkg/api/users_test.go (1)

5-5: LGTM! Consider adding authentication-aware tests.

The changes correctly adapt to the new addUserRoutes signature. Using authlib.NewNoAuth() is appropriate for testing core CRUD functionality without authentication complexity.

However, since this PR adds scope checks, consider adding complementary tests that:

  • Verify authentication is properly enforced on user routes
  • Validate scope-based authorization (e.g., ensure certain operations require specific scopes)
  • Test negative cases where requests without proper authentication/scopes are rejected

Also applies to: 90-90

test/e2e/oauth2_clients_test.go (1)

722-739: Consider enhancing the delete secret authorization test.

The test uses a dummy secret ID (line 732) because the unauthorized client cannot read the client to obtain a real secret ID. While this still validates that unauthorized requests are rejected, it's ambiguous whether the failure is due to:

  1. Authorization failure (intended test)
  2. Non-existent secret (side effect)

Consider one of these approaches for clearer intent:

  1. Store the real secret ID during the setup (lines 602-609) in a variable accessible to this test
  2. Add a comment clarifying that either failure mode (auth or not-found) is acceptable for security
  3. If the API fails-fast on authorization before resource lookup, document that guarantee

Example enhancement:

  When("trying to delete a secret", func() {
+   var realSecretID string
    var (
      err error
    )

    BeforeEach(func() {
-     // First, we need to get the secret ID from the client
-     // But we can't read the client, so we'll use a dummy ID
+     // Note: Using a real secret ID from setup to test authorization,
+     // not resource existence. The API should reject based on scope
+     // before checking if the resource exists.
+     realSecretID = // capture from lines 602-609 setup
      _, err = srv.Client(unauthorizedHTTPClient).Auth.V1.DeleteSecret(ctx, operations.DeleteSecretRequest{
        ClientID: unauthorizedClientID,
-       SecretID: "dummy-secret-id",
+       SecretID: realSecretID,
      })
    })
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0af8f5d and 6307dad.

⛔ Files ignored due to path filters (16)
  • go.sum is excluded by !**/*.sum
  • pkg/client/.speakeasy/gen.lock is excluded by !**/*.lock, !pkg/client/**
  • pkg/client/.speakeasy/gen.yaml is excluded by !pkg/client/**
  • pkg/client/docs/models/components/client.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/clientsecret.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/createclientrequest.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/createsecretrequest.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/secret.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/updateclientrequest.md is excluded by !pkg/client/**
  • pkg/client/formance.go is excluded by !pkg/client/**
  • pkg/client/models/components/client.go is excluded by !pkg/client/**
  • pkg/client/models/components/clientsecret.go is excluded by !pkg/client/**
  • pkg/client/models/components/createclientrequest.go is excluded by !pkg/client/**
  • pkg/client/models/components/createsecretrequest.go is excluded by !pkg/client/**
  • pkg/client/models/components/secret.go is excluded by !pkg/client/**
  • pkg/client/models/components/updateclientrequest.go is excluded by !pkg/client/**
📒 Files selected for processing (18)
  • .coderabbit.yaml (1 hunks)
  • .github/dependabot.yml (0 hunks)
  • cmd/serve.go (4 hunks)
  • go.mod (3 hunks)
  • openapi.yaml (1 hunks)
  • pkg/api/authorization/accesstoken.go (0 hunks)
  • pkg/api/authorization/accesstoken_test.go (0 hunks)
  • pkg/api/authorization/main_test.go (0 hunks)
  • pkg/api/authorization/middleware.go (0 hunks)
  • pkg/api/clients.go (3 hunks)
  • pkg/api/clients_test.go (2 hunks)
  • pkg/api/module.go (2 hunks)
  • pkg/api/users.go (2 hunks)
  • pkg/api/users_test.go (2 hunks)
  • pkg/oidc/storage.go (1 hunks)
  • pkg/testserver/server.go (3 hunks)
  • test/e2e/client_credentials_test.go (2 hunks)
  • test/e2e/oauth2_clients_test.go (1 hunks)
💤 Files with no reviewable changes (5)
  • pkg/api/authorization/accesstoken_test.go
  • pkg/api/authorization/accesstoken.go
  • pkg/api/authorization/middleware.go
  • .github/dependabot.yml
  • pkg/api/authorization/main_test.go
🚧 Files skipped from review as they are similar to previous changes (9)
  • test/e2e/client_credentials_test.go
  • go.mod
  • pkg/api/module.go
  • pkg/testserver/server.go
  • pkg/api/clients.go
  • pkg/api/clients_test.go
  • pkg/api/users.go
  • pkg/oidc/storage.go
  • .coderabbit.yaml
🧰 Additional context used
🧬 Code graph analysis (2)
cmd/serve.go (4)
pkg/api/module.go (1)
  • Module (46-66)
pkg/storage/sqlstorage/module.go (1)
  • Module (19-40)
pkg/oidc/module.go (1)
  • Module (19-43)
pkg/oidc/storage.go (2)
  • Service (89-91)
  • KeyID (551-551)
test/e2e/oauth2_clients_test.go (10)
pkg/testserver/server.go (4)
  • Server (69-77)
  • New (279-299)
  • Configuration (54-63)
  • DelegatedConfiguration (42-46)
pkg/client/models/components/clientsecret.go (1)
  • ClientSecret (5-10)
pkg/client.go (2)
  • StaticClient (118-121)
  • ClientOptions (154-164)
pkg/client/models/components/client.go (1)
  • Client (5-16)
pkg/client/models/components/createclientrequest.go (1)
  • CreateClientRequest (5-14)
pkg/client/models/operations/readclient.go (1)
  • ReadClientRequest (9-12)
pkg/client/models/components/updateclientrequest.go (1)
  • UpdateClientRequest (5-14)
pkg/client/models/operations/deleteclient.go (2)
  • DeleteClientResponse (21-23)
  • DeleteClientRequest (9-12)
pkg/client/models/components/createsecretrequest.go (1)
  • CreateSecretRequest (5-8)
pkg/client/models/operations/deletesecret.go (1)
  • DeleteSecretRequest (9-14)
🔇 Additional comments (12)
test/e2e/oauth2_clients_test.go (7)

1-20: LGTM! Clean test setup.

The build tag, package declaration, and imports are appropriate for an E2E test suite. The use of Ginkgo/Gomega framework and OAuth2 client credentials flow aligns well with testing OAuth2 client management endpoints.


22-52: LGTM! Comprehensive test server configuration.

The test setup properly configures:

  • PostgreSQL backend for persistence
  • OIDC delegated authentication
  • A static client with auth:write scope for authorized operations
  • CheckScopes: true to enable scope validation testing

This provides a solid foundation for testing both authorized and unauthorized access patterns.


69-369: LGTM! Comprehensive CRUD test coverage.

The client CRUD tests are well-structured and thorough:

  • Proper separation of minimal vs. full field creation scenarios
  • Validation of all returned fields
  • Edge case handling (non-existent resources)
  • Persistence verification after updates (lines 340-351)

The use of nested When blocks makes the test intent clear and follows BDD best practices.


410-427: Verify idempotent delete behavior is intentional.

The test accepts both 204 No Content and 404 Not Found for deleting a non-existent client. While the comment indicates this is expected idempotent behavior, accepting two different status codes could mask inconsistent API implementation.

Consider verifying:

  1. What is the intended API contract for deleting non-existent resources?
  2. Should the behavior be deterministic (always return the same status code)?

If the dual behavior is intentional, consider documenting why both status codes are acceptable in this context.


431-572: LGTM! Thorough secret management test coverage.

The secret management tests are comprehensive and well-designed:

  • Verifies the complete secret structure including clear text and last digits (lines 467-474)
  • Tests cumulative state with multiple secrets (lines 489-515)
  • Properly validates that secrets are reflected in the parent client (lines 476-487)
  • Good coverage of error scenarios (non-existent secret/client)

The clear text secret is correctly verified only in the creation response, not in subsequent reads, which aligns with security best practices.


575-619: LGTM! Excellent unauthorized access test setup.

The unauthorized client setup is well-designed:

  • Uses the authorized global client to create the test client
  • Deliberately omits auth:write scope (line 595)
  • Creates a realistic scenario where a client exists but lacks required permissions

This setup enables comprehensive authorization testing across all endpoints.


621-720: LGTM! Comprehensive authorization coverage.

The unauthorized access tests provide excellent security coverage by validating that all client and secret operations are properly protected:

  • CRUD operations for clients (create, list, read, update, delete)
  • Secret operations (create, delete)

All tests correctly expect errors when operations are attempted without the auth:write scope. This is critical for validating the scope-check functionality introduced in this PR.

cmd/serve.go (5)

82-99: LGTM - Good refactoring for reusability.

The extraction of otlpHttpClient into a separate helper function improves code organization and reusability. The switch from fx.Provide to fx.Decorate appropriately decorates the HTTP client in the dependency graph.


114-114: LGTM - Safe opt-in default.

The scope checking flag defaults to false, ensuring backward compatibility. This allows existing deployments to continue without scope enforcement until explicitly enabled.


8-10: Import statements are correct and all exported symbols are properly used.

The verification confirms:

  • Dependencies are present in go.mod with appropriate versions
  • authlib.AuthCheckScopesFlag, authlib.Module, and authlib.ModuleConfig are all properly exported and used
  • oidclib.KeySet, oidclib.NewStaticKeySet, and oidclib.KeyUseSignature are all properly exported and used
  • go-jose/v4 is properly imported and used for jose.JSONWebKey

195-200: Verify that authlib.ModuleConfig in github.com/formancehq/go-libs/v3 v3.3.1 supports all four fields used: Enabled, Issuer, CheckScopes, and Service.

The external dependency structure cannot be verified within the codebase. Confirm the struct definition in formancehq/go-libs matches the configuration passed at cmd/serve.go lines 195-200.


201-208: LGTM - KeySet configuration is correct.

The static KeySet decoration properly provides the server's public key for JWT verification:

  • Using the server's own public key is appropriate for verifying self-issued tokens
  • KeyID: oidc.KeyID matches the constant defined in the codebase (value: "id")
  • Algorithm: RS256 and Use: oidclib.KeyUseSignature are standard for JWT verification
  • All constants (oidclib.KeyUseSignature, oidclib.NewStaticKeySet, oidclib.KeySet) are valid exports from github.com/formancehq/go-libs/v3/oidc

flemzord
flemzord previously approved these changes Nov 6, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/api/module.go (1)

58-58: Remove the unused op.OpenIDProvider parameter from the fx.Invoke function.

The variable o is declared in the function signature but never referenced in the function body (lines 59-63). It should be removed since it provides no value and indicates incomplete refactoring after removing it from CreateRootRouter.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1a17c01 and d3d0c5b.

⛔ Files ignored due to path filters (16)
  • go.sum is excluded by !**/*.sum
  • pkg/client/.speakeasy/gen.lock is excluded by !**/*.lock, !pkg/client/**
  • pkg/client/.speakeasy/gen.yaml is excluded by !pkg/client/**
  • pkg/client/docs/models/components/client.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/clientsecret.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/createclientrequest.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/createsecretrequest.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/secret.md is excluded by !pkg/client/**
  • pkg/client/docs/models/components/updateclientrequest.md is excluded by !pkg/client/**
  • pkg/client/formance.go is excluded by !pkg/client/**
  • pkg/client/models/components/client.go is excluded by !pkg/client/**
  • pkg/client/models/components/clientsecret.go is excluded by !pkg/client/**
  • pkg/client/models/components/createclientrequest.go is excluded by !pkg/client/**
  • pkg/client/models/components/createsecretrequest.go is excluded by !pkg/client/**
  • pkg/client/models/components/secret.go is excluded by !pkg/client/**
  • pkg/client/models/components/updateclientrequest.go is excluded by !pkg/client/**
📒 Files selected for processing (18)
  • .coderabbit.yaml (1 hunks)
  • .github/dependabot.yml (0 hunks)
  • cmd/serve.go (4 hunks)
  • go.mod (4 hunks)
  • openapi.yaml (1 hunks)
  • pkg/api/authorization/accesstoken.go (0 hunks)
  • pkg/api/authorization/accesstoken_test.go (0 hunks)
  • pkg/api/authorization/main_test.go (0 hunks)
  • pkg/api/authorization/middleware.go (0 hunks)
  • pkg/api/clients.go (3 hunks)
  • pkg/api/clients_test.go (2 hunks)
  • pkg/api/module.go (2 hunks)
  • pkg/api/users.go (2 hunks)
  • pkg/api/users_test.go (2 hunks)
  • pkg/oidc/storage.go (1 hunks)
  • pkg/testserver/server.go (3 hunks)
  • test/e2e/client_credentials_test.go (2 hunks)
  • test/e2e/oauth2_clients_test.go (1 hunks)
💤 Files with no reviewable changes (5)
  • pkg/api/authorization/accesstoken.go
  • pkg/api/authorization/accesstoken_test.go
  • pkg/api/authorization/middleware.go
  • pkg/api/authorization/main_test.go
  • .github/dependabot.yml
🚧 Files skipped from review as they are similar to previous changes (5)
  • test/e2e/oauth2_clients_test.go
  • pkg/api/clients.go
  • pkg/api/users_test.go
  • pkg/testserver/server.go
  • pkg/oidc/storage.go
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/serve.go (2)
pkg/oidc/module.go (1)
  • Module (19-43)
pkg/oidc/storage.go (2)
  • Service (89-91)
  • KeyID (551-551)
🔇 Additional comments (7)
pkg/api/clients_test.go (2)

5-5: LGTM! Clean import alias to avoid package name conflict.

The authlib alias cleanly distinguishes the authentication library from the local auth package imported on line 19.


44-44: LGTM! Appropriate use of NoAuth for unit tests.

Passing authlib.NewNoAuth() is the correct approach for unit tests that focus on API logic without requiring actual authentication.

pkg/api/users.go (2)

4-4: LGTM! Clean import alias.

The authlib alias is consistent with the pattern used in clients_test.go and avoids conflicts with the local auth package.


14-15: LGTM! Clean dependency injection pattern.

The authenticator is properly injected as a parameter and applied as middleware to the entire /users route group. This aligns with the PR's objective of adding scope checks via authlib.

pkg/api/module.go (3)

18-22: LGTM! Cleaner router initialization.

Removing the OpenIDProvider parameter from CreateRootRouter simplifies the initialization. The issuer is still properly propagated via op.ContextWithIssuer on line 35.


50-51: LGTM! Simplified provider function.

The provider function now correctly depends only on the logger, with issuer and debug captured from the enclosing scope.


55-56: The authenticator appears to be properly provided through the authlib.Module dependency.

Based on the codebase analysis:

  1. authlib.Module() is supplied to the fx dependency graph in cmd/serve.go at line 195
  2. Both addClientRoutes and addUserRoutes require authlib.Authenticator as a parameter
  3. These functions are invoked via fx.Invoke() in pkg/api/module.go

The fx dependency resolver would fail at runtime if authlib.Authenticator were not available through authlib.Module. Since authlib.Module is from the external library github.com/formancehq/go-libs/v3/auth, I cannot definitively verify its exports through public documentation. However, the code structure suggests the dependency is correctly satisfied.

@gfyrag gfyrag merged commit 5373fa4 into main Nov 6, 2025
6 checks passed
@gfyrag gfyrag deleted the fix/add-scopes branch November 6, 2025 13:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants